package com.camel.docker.utils;

import com.camel.docker.entity.docker.Env;
import com.camel.docker.entity.docker.PortMap;
import com.camel.docker.entity.docker.Volume;
import com.camel.docker.entity.search.ContainerAddForm;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.*;
import com.github.pagehelper.util.StringUtil;
import lombok.Data;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Data
public class DockerUtils {

    private String ftp_base_path;

    private static DockerUtils singleton = null;

    public DockerUtils() {
    }

    public static DockerUtils getInstance() {
        if (singleton == null) {
            singleton = new DockerUtils();
        }
        return singleton;
    }

    public CreateContainerResponse createContainer(ContainerAddForm containerAddForm, DockerClient client) {
        // 准备配置数据
        // 得到卷配置
        List<Mount> mounts = loadMountConfig(containerAddForm.getVolumes());
        // 得到需要映射的端口以及内外映射的端口
        List<ExposedPort> exposedPortListConfig = loadExposedPorts(containerAddForm.getPorts());
        List<PortBinding> portBindingListConfig = loadBindingLists(containerAddForm.getPorts());
        // 准备环境变量的配置数据
        List<String> envs = loadEnvs(containerAddForm.getEnvs());
        // 准备主机配置数据
        HostConfig hostConfig = HostConfig.newHostConfig();
        if (!CollectionUtils.isEmpty(portBindingListConfig)) {
            hostConfig.withPortBindings(portBindingListConfig);
        }
        if (!CollectionUtils.isEmpty(mounts)) {
            hostConfig.withMounts(mounts);
        }
        Map<String, String> labels = new HashMap<>();
        labels.put("pname", containerAddForm.getName());
        // 配置并创建容器
        CreateContainerCmd createContainerCmd = client.createContainerCmd(containerAddForm.getImage())
                .withLabels(labels)
                .withHostConfig(hostConfig)
                .withTty(true)
                .withAttachStdin(true)
                .withEnv(envs);
        if (StringUtil.isNotEmpty(containerAddForm.getWorkDir())) {
            createContainerCmd.withWorkingDir(containerAddForm.getWorkDir());
        }
        if (!CollectionUtils.isEmpty(exposedPortListConfig)) {
            createContainerCmd.withExposedPorts(exposedPortListConfig);
        }

        if (StringUtil.isNotEmpty(containerAddForm.getDirective())) {
            createContainerCmd.withCmd(CollectionUtils.arrayToList(containerAddForm.getDirective().split(" ")));
        }
        return createContainerCmd.exec();
    }


    private List<ExposedPort> loadExposedPorts(List<PortMap> ports) {
        List<ExposedPort> exposedPortList = new ArrayList<>();
        for (PortMap port : ports) {
            exposedPortList.add(ExposedPort.tcp(port.getPortT()));
        }
        return exposedPortList;
    }

    private List<PortBinding> loadBindingLists(List<PortMap> ports) {
        List<PortBinding> portBindingList = new ArrayList<>();
        for (PortMap port : ports) {
            PortBinding portBinding = new PortBinding(Ports.Binding.bindPort(port.getPortF()), ExposedPort.tcp(port.getPortT()));
            portBindingList.add(portBinding);
        }
        return portBindingList;
    }


    private List<String> loadEnvs(List<Env> envs) {
        List<String> envList = new ArrayList<>();
        for (Env env : envs) {
            if (StringUtil.isNotEmpty(env.getKey()) && StringUtil.isNotEmpty(env.getValue())) {
                envList.add(env.getKey() + "=" + env.getValue());
            }
        }
        return envList;
    }

    private List<Mount> loadMountConfig(List<Volume> volumeList) {
        List<Mount> mounts = new ArrayList<>();
        if(CollectionUtils.isEmpty(volumeList)) {
            return mounts;
        }
        String basePath = StringUtils.isEmpty(PropertyUtil.getProperty("baseUrl")) ? "/" : PropertyUtil.getProperty("baseUrl");
        for (com.camel.docker.entity.docker.Volume v : volumeList) {
            if (StringUtil.isNotEmpty(v.getRouteF()) && StringUtil.isNotEmpty(v.getRouteT())) {
                Mount mount = new Mount();
                mount.withType(MountType.BIND);
                mount.withSource(basePath + v.getRouteF());
                mount.withTarget(v.getRouteT());
                mounts.add(mount);
            }
        }
        return mounts;
    }
}
